﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace Common.Utils
{
    public static class SerializationUtil
    {
        public static void SerializeBaseType(object obj, SerializationInfo info, StreamingContext context)
        {
            Type baseType = obj.GetType().BaseType;
            SerializeType(obj, baseType, info, context);
        }

        public static void SerializeType(object obj, Type type, SerializationInfo info, StreamingContext context)
        {
            //利用反射序列化字段
            if (type == typeof(object))
            {
                return;
            }

            BindingFlags flags = BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic |
                                 BindingFlags.Public;
            FieldInfo[] fields = type.GetFields(flags);
            foreach (FieldInfo field in fields)
            {
                if (field.IsNotSerialized)
                {
                    continue;
                }

                string fieldName = type.Name + "+" + field.Name;
                info.AddValue(fieldName, field.GetValue(obj));
            }

            SerializeType(obj, type.BaseType, info, context);
        }

        /// <summary>
        /// 序列化一个类
        /// </summary>
        /// <param name="obj">指定序列化的类</param>
        /// <param name="type">序列化类的类型</param>
        /// <param name="info">操作序列化的对象(序列化的工具)</param>
        /// <param name="context"></param>
        /// <param name="ignore">忽略指定序列化的类型</param>
        public static void SerializeType(object obj, Type type, SerializationInfo info, StreamingContext context, Type ignore)
        {
            //利用反射序列化字段
            if (type == typeof(object))
            {
                return;
            }

            if (type == ignore)
            {
                return;
            }

            BindingFlags flags = BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic |
                                 BindingFlags.Public;
            FieldInfo[] fields = type.GetFields(flags);
            foreach (FieldInfo field in fields)
            {
                if (field.IsNotSerialized)
                {
                    continue;
                }

                string fieldName =  field.Name;//获取字段的名称
                info.AddValue(fieldName, field.GetValue(obj));
            }

            // 继续序列化父类信息
            SerializeType(obj, type.BaseType, info, context, ignore);
        }



        public static void DeserializeBaseType(object obj, SerializationInfo info, StreamingContext context)
        {
            Type baseType = obj.GetType().BaseType;
            DeserializeType(obj, baseType, info, context);
        }

        public static void DeserializeType(object obj, Type type, SerializationInfo info, StreamingContext context)
        {
            if (type == typeof(object))
            {
                return;
            }

            BindingFlags flags = BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic |
                                 BindingFlags.Public;
            FieldInfo[] fields = type.GetFields(flags);
            foreach (FieldInfo field in fields)
            {
                if (field.IsNotSerialized)
                {
                    continue;
                }

                string fieldName = type.Name + "+" + field.Name;
                object fieldValue = info.GetValue(fieldName, field.FieldType);
                field.SetValue(obj, fieldValue);
            }

            DeserializeType(obj, type.BaseType, info, context);
        } //Rest of SerializationUtil }

        public static void DeserializeType(object obj, Type type, SerializationInfo info, StreamingContext context, Type ignoreType)
        {
            if (type == typeof(object))
            {
                return;
            }
            if (type == ignoreType)
            {
                return;
            }

            BindingFlags flags = BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic |
                                 BindingFlags.Public;
            FieldInfo[] fields = type.GetFields(flags);
            foreach (FieldInfo field in fields)
            {
                if (field.IsNotSerialized)
                {
                    continue;
                }

                string fieldName =  field.Name;
                object fieldValue = info.GetValue(fieldName, field.FieldType);
                field.SetValue(obj, fieldValue);
            }

            DeserializeType(obj, type.BaseType, info, context, ignoreType);
        } //Rest of SerializationUtil }
    }
}
